﻿using AutomaticScrewLocking.domain.autoTest.model.aggregates;
using AutomaticScrewLocking.domain.localLog.service;
using AutomaticScrewLocking.domain.localLog.service.impl;
using AutomaticScrewLocking.domain.modbus.comm.service;
using AutomaticScrewLocking.types;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Threading;
using System.Threading.Tasks;

namespace AutomaticScrewLocking.domain.autoTest.service.impl
{
    /// <summary>
    /// 自动测试服务实现类
    /// </summary>
    public class AutoTestServiceImpl : AutoTestService
    {
        private SerialPort serialPort;
        private PlcCommunicationService plcCommunicationService;
        private LogService logService;
        private string errorMsg = string.Empty;
        private bool result = false;
        private List<byte> torqueList = new List<byte>();



        // 状态机委托
        private Action stateMachine;
        CancellationToken cancellationToken;
        CancellationTokenSource tokenSource;
       


        public AutoTestServiceImpl(AutoTestParam autoTestParam)
        {
            this.serialPort = autoTestParam.serialPort;
            this.plcCommunicationService = autoTestParam.PlcCommunicationService;
            this.logService = new LogServiceImpl();
            this.tokenSource = new CancellationTokenSource();
            this.cancellationToken = tokenSource.Token;   
        }

        /// <summary>
        /// 开始测试
        /// </summary>
        public void startTest()
        {
            stateMachine = initialTest;
            Task.Run(new Action(Run));
        }
        
        
        /// <summary>
        /// 停止测试
        /// </summary>
        public void stopTest()
        {
            exportLog("停止自动测试");
            tokenSource.Cancel();
        }


        private void Run()
        {
            while (true)
            {
                stateMachine();
                Thread.Sleep(5);
                if (tokenSource.IsCancellationRequested)
                {
                    break;
                }
            }
        }

        /// <summary>
        /// 初始化测试（向PLC中写入锁付的起始坐标和结束坐标）
        /// </summary>
        private void initialTest()
        {
            exportLog("开始自动测试");
            plcCommunicationService.WriteStartPosZ(GlobalParam.getInstance().param.startPos, out errorMsg);
            plcCommunicationService.WriteEndPosZ(GlobalParam.getInstance().param.endPos, out errorMsg);
            // 切换状态(读取开始测试信号)
            stateMachine = readStartTest;
        }

        /// <summary>
        /// 读取开始测试信号
        /// </summary>
        private void readStartTest()
        {
            // 从PLC中读取开始测试信号
            if (plcCommunicationService.ReadStartSignal(out result, out errorMsg) == 1)
            {
                exportLog("读取到PLC开始锁付信号");
                // 读取到开始测试信号后，向PLC写入2表示数据读取成功
                plcCommunicationService.writeStartSignal(out errorMsg);
                // 切换状态(读取扭力值)
                stateMachine = readTorque;
            }
        }

        /// <summary>
        /// 读取扭力值
        /// </summary>
        private void readTorque()
        {
            // 从PLC中读取结束测试信号
            if (plcCommunicationService.ReadEndSignal(out result, out errorMsg) == 1)
            {
                exportLog("读取到PLC结束锁付信号");
                // 读取到结束测试信号后，向PLC写入2表示数据读取成功
                plcCommunicationService.WriteEndSignal(out errorMsg);
                // 切换状态(更新UI)
                stateMachine = updateUi;
            }
            else
            {
                int nums = serialPort.BytesToRead;
                if (nums > 0)
                {
                    byte[] bytes = new byte[nums];
                    serialPort.Read(bytes, 0, bytes.Length);
                    torqueList.AddRange(bytes);
                }
            }
                
        }

        /// <summary>
        /// 更新UI
        /// </summary>
        private void updateUi()
        {
            
            if (torqueList.Count > 0)
            {
                exportLog("开始更新界面数据");
                // 刷新界面
                GlobalDelegate.updateDataDelegate(torqueList);
            }
            else
            {
                exportLog("无数据，不需要更新界面数据");
            }

            // 切换状态(读取开始测试信号)
            stateMachine = readStartTest;
        }

        /// <summary>
        /// 输出日志
        /// </summary>
        /// <param name="message"></param>
        private void exportLog(string message)
        {
            GlobalDelegate.updateUiLogDelegate(message);
            logService.WriteLog(message);
        }
    }
}
